<?php
namespace app\command;
use app\framework\lib\Log;
use app\framework\lib\Redis;

abstract class command
{
    /**
     *
     * @var string
     */
    public string $processName = "";
    public int $seconds = 0;

    public function __construct(string $processName, int $seconds)
    {
        $this->processName = $processName;
        $this->seconds = $seconds;
    }

    public function lock()
    {
        $maxRetries = 10;
        $retryDelay = 200; // microseconds
        $retryCount = 0;

        while ($retryCount < $maxRetries) {
            if ($this->tryLock($this->processName)) {
                return true;
            }
            $retryCount++;
            $retryDelay = min($retryDelay * 2, 1000000); // Exponential backoff, max 1 second
            usleep($retryDelay);
        }

        Log::error("加锁失败，已达到最大重试次数: {$this->processName}");
        return false;
    }



    public function tryLock($key, $value = '1')
    {
        $ok = Redis::set("lock_" . $key, $value, ["nx", "ex" => $this->seconds]);
        if ($ok) {
            Log::info("lock_{$key}加锁成功");
        } else {
            Log::warning("lock_{$key}加锁失败");
        }
        return $ok;
    }



    public function unlock($value = '1')
    {
        $script = <<< EOF
if (redis.call("get", "lock_" .. KEYS[1]) == ARGV[1]) then
	return redis.call("del", "lock_" .. KEYS[1])
else
	return 0
end
EOF;
        $result = Redis::eval($script, [$this->processName, $value], 1) > 0;
        if ($result) {
            Log::info("lock_{$this->processName}解锁成功");
        } else {
            Log::warning("lock_{$this->processName}解锁失败");
        }
        return $result;
    }
    //执行任务
    abstract public function run();

}
